home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-19 / iritsm3s.zip / IRITPRSR.C < prev    next >
C/C++ Source or Header  |  1992-02-29  |  29KB  |  923 lines

  1. /*****************************************************************************
  2. * Generic parser for the "Irit" solid modeller.                     *
  3. *                                         *
  4. * Written by:  Gershon Elber                Ver 0.2, Sep. 1991   *
  5. *****************************************************************************/
  6.  
  7. #ifdef __MSDOS__
  8. #include <stdlib.h>
  9. #endif /* __MSDOS__ */
  10.  
  11. #include <stdio.h>
  12. #include <ctype.h>
  13. #include <math.h>
  14. #include <string.h>
  15. #include <setjmp.h>
  16. #include "irit_sm.h"
  17. #include "iritprsr.h"
  18.  
  19. #define LOAD_COLOR              14        /* Index color 1 by default. */
  20.  
  21. #define UNGET_STACK_SIZE    5             /* Internal stack size. */
  22.  
  23. typedef enum {              /* List of all possible tokens enumerated. */
  24.     TOKEN_NONE,
  25.  
  26.     TOKEN_OPEN_PAREN,
  27.     TOKEN_CLOSE_PAREN,
  28.  
  29.     TOKEN_E2,
  30.     TOKEN_P2,
  31.     TOKEN_E3,
  32.     TOKEN_P3,
  33.  
  34.     TOKEN_NUMBER,
  35.     TOKEN_STRING,
  36.     TOKEN_VECTOR,
  37.     TOKEN_MATRIX,
  38.     TOKEN_CTLPT,
  39.     TOKEN_VERTEX,
  40.     TOKEN_POLYGON,
  41.     TOKEN_POLYLINE,
  42.     TOKEN_POINTLIST,
  43.     TOKEN_OBJECT,
  44.     TOKEN_COLOR,
  45.     TOKEN_RGB,
  46.     TOKEN_INTERNAL,
  47.     TOKEN_NORMAL,
  48.     TOKEN_PLANE,
  49.     TOKEN_CURVE,
  50.     TOKEN_SURFACE,
  51.  
  52.     TOKEN_OTHER    = 100,            /* Probably names & numbers. */
  53.     TOKEN_EOF = -1
  54. } TokenType;
  55.  
  56. typedef enum {             /* Possible error code during data parsing. */
  57.     IP_NO_ERR = 0,
  58.  
  59.     IP_ERR_NUMBER_EXPECTED,
  60.     IP_ERR_OPEN_PAREN_EXPECTED,
  61.     IP_ERR_CLOSE_PAREN_EXPECTED,
  62.     IP_ERR_LIST_COMP_UNDEF,
  63.     IP_ERR_UNDEF_EXPR_HEADER,
  64.     IP_ERR_PT_TYPE_EXPECTED,
  65.     IP_ERR_OBJECT_EMPTY,
  66.     IP_ERR_MIXED_TYPES,
  67.     IP_STR_NOT_IN_QUOTES,
  68.     IP_ERR_OBJECT_EXPECTED,
  69.     IP_ERR_CAGD_LIB_ERR,
  70.     IP_ERR_STACK_OVERFLOW,
  71.     IP_ERR_DEGEN_POLYGON,
  72.  
  73.     IP_WRN_OBJ_NAME_TRUNC = 100
  74. } IritPrsrErrType;
  75.  
  76. static int  IPGlblLineCount = 0;     /* Used to locate errors in input file. */
  77. static IritPrsrErrType IPGlblParserError = IP_NO_ERR;   /* Last err # found. */
  78. static char IPGlblTokenError[LINE_LEN_LONG];  /* Last token error was found. */
  79. static jmp_buf LclLongJumpBuffer;           /* Used in error traping. */
  80. static int  GlblToken =    0,          /* Used by the parser, to unget token. */
  81.         GlblLineCount = 1;         /* Used to locate errors in input file. */
  82. static char GlblStringToken[UNGET_STACK_SIZE][LINE_LEN_LONG];/* Unget tokens.*/
  83.  
  84. static IPObjectStruct *AllSrfs = NULL;
  85. static IPObjectStruct *AllCrvs = NULL;
  86. static IPObjectStruct *AllPolys = NULL;
  87.  
  88. int IritPrsrPolyListCirc = TRUE;
  89. int IritPrsrWasViewMat = FALSE,
  90.     IritPrsrWasPrspMat = FALSE;
  91. MatrixType IritPrsrViewMat = {              /* Isometric view, by default. */
  92.     { -0.707107, -0.408248, 0.577350, 0.000000 },
  93.     {  0.707107, -0.408248, 0.577350, 0.000000 },
  94.     {  0.000000,  0.816496, 0.577350, 0.000000 },
  95.     {  0.000000,  0.000000, 0.000000, 1.000000 }
  96. };
  97. MatrixType IritPrsrPrspMat = {
  98.     { 1, 0, 0, 0 },
  99.     { 0, 1, 0, 0 },
  100.     { 0, 0, 0.1, -0.35 },
  101.     { 0, 0, 0.35, 1.0 }
  102. };
  103.  
  104. static void UnGetToken(char *StringToken);
  105. static void GetStringToken(FILE *f, char *StringToken);
  106. static TokenType GetToken(FILE *f, char *StringToken);
  107. static void GetVertexAttributes(IPVertexStruct *PVertex, FILE *f);
  108. static void GetPolygonAttributes(IPPolygonStruct *PPolygon, FILE *f);
  109. static void GetObjectAttributes(IPObjectStruct *PObject, FILE *f);
  110. static void GetPointData(FILE *f, IPPolygonStruct *PPolygon);
  111. static void IPUpdatePolyPlane(IPPolygonStruct *PPoly);
  112. static void ParserError(IritPrsrErrType ErrNum, char *Msg);
  113.  
  114. static void IritPrsrGetAllObjects(FILE *f, IPObjectStruct *PObjParent);
  115. static void GetCloseParenToken(FILE *f);
  116. static void SkipToCloseParenToken(FILE *f);
  117. static void GetNumericToken(FILE *f, RealType *r);
  118. static void IritPrsrGetAuxObject(FILE *f, IPObjectStruct *PObj);
  119.  
  120. /*****************************************************************************
  121. * Routine to read the data from    a given    file.                     *
  122. *****************************************************************************/
  123. IPObjectStruct *IritPrsrGetObjects(FILE *f)
  124. {
  125.     IPObjectStruct *PObjs, *PTmp;
  126.  
  127.     AllSrfs = NULL;
  128.     AllCrvs = NULL;
  129.     AllPolys = NULL;
  130.  
  131.     /* If the following gain control and is non zero - its from error! */
  132.     if (setjmp(LclLongJumpBuffer) != 0) {
  133.     if (f != NULL) fclose(f);
  134.     return NULL;
  135.     }
  136.  
  137.     GlblToken =    0;             /* Used in UnGetToken token buffer. */
  138.     IPGlblParserError = IP_NO_ERR;                /* Reset errors. */
  139.     GlblLineCount = 1;                      /* Reset line counter. */
  140.  
  141.     PTmp = IritPrsrNewObjectStruct();
  142.     IritPrsrGetAllObjects(f, PTmp);
  143.  
  144.     if (AllCrvs != NULL || AllSrfs != NULL) {
  145.     if ((PObjs = IritPrsrProcessFreeForm(AllCrvs, AllSrfs)) != NULL)
  146.         {
  147.         for (PTmp = PObjs; PTmp -> Pnext != NULL; PTmp = PTmp -> Pnext) {
  148.         if (!IP_HAS_OBJ_COLOR(PTmp)) {
  149.             PTmp -> Color = LOAD_COLOR;
  150.             IP_SET_OBJ_COLOR(PTmp);
  151.         }
  152.         }
  153.         PTmp -> Pnext = AllPolys;
  154.         AllPolys = PObjs;
  155.         }
  156.     }
  157.  
  158.     fclose(f);
  159.     return AllPolys;
  160. }
  161.  
  162. /*****************************************************************************
  163. * Routine to read the geometry data from a given file. Reads "[OBJECT ..."   *
  164. * prefixes only and invoke the auxiliary routine.                 *
  165. * Note objects may be recursively defined.                     *
  166. *****************************************************************************/
  167. static void IritPrsrGetAllObjects(FILE *f, IPObjectStruct *PObjParent)
  168. {
  169.     char StringToken[LINE_LEN_LONG];
  170.     TokenType Token;
  171.     int    WasObjectToken = FALSE,
  172.     Quit = FALSE;
  173.     IPObjectStruct *PObj;
  174.  
  175.     while (!Quit) {
  176.         while ((Token = GetToken(f, StringToken)) != TOKEN_OPEN_PAREN &&
  177.            Token != TOKEN_CLOSE_PAREN &&
  178.            Token != TOKEN_EOF);
  179.  
  180.     if (Token == TOKEN_CLOSE_PAREN || Token == TOKEN_EOF)
  181.     {
  182.         if (Token == TOKEN_CLOSE_PAREN)
  183.         UnGetToken(StringToken);
  184.         Quit = TRUE;
  185.         break;
  186.     }
  187.  
  188.     switch (GetToken(f, StringToken)) {
  189.         case TOKEN_OBJECT:
  190.         WasObjectToken = TRUE;
  191.         PObj = IritPrsrNewObjectStruct();
  192.  
  193.         /* The following handle optional attributes in record. */
  194.         if (GetToken(f, StringToken) == TOKEN_OPEN_PAREN)
  195.             GetObjectAttributes(PObj, f);
  196.         else
  197.         {
  198.             UnGetToken(StringToken);
  199.         }
  200.  
  201.         if (!IP_HAS_OBJ_COLOR(PObj)) {
  202.             PObj -> Color = LOAD_COLOR;
  203.             IP_SET_OBJ_COLOR(PObj);
  204.         }
  205.  
  206.         if (GetToken(f, StringToken) == TOKEN_OTHER &&
  207.             strcmp(StringToken, "NONE") != 0)
  208.             strcpy(PObj -> Name, StringToken);
  209.  
  210.         IritPrsrGetAllObjects(f, PObj);
  211.  
  212.         GetCloseParenToken(f);
  213.         if (PObjParent) {
  214.             /* This object contains other object - delete it since   */
  215.             /* we are flattening the structure here.             */
  216.             free((VoidPtr) PObjParent);
  217.             PObjParent = NULL;
  218.         }
  219.         break;
  220.         default:
  221.         if (WasObjectToken) {
  222.             ParserError(IP_ERR_OBJECT_EXPECTED, StringToken);
  223.         }
  224.         UnGetToken(StringToken);
  225.         UnGetToken("[");
  226.         IritPrsrGetAuxObject(f, PObjParent);
  227.         Quit = TRUE;
  228.         break;
  229.     }
  230.     }
  231. }
  232.  
  233. /*****************************************************************************
  234. * Routine to get close paren token from f.                     *
  235. *****************************************************************************/
  236. static void GetCloseParenToken(FILE *f)
  237. {
  238.     char StringToken[LINE_LEN_LONG];
  239.  
  240.     if (GetToken(f, StringToken) != TOKEN_CLOSE_PAREN)
  241.     ParserError(IP_ERR_CLOSE_PAREN_EXPECTED, StringToken);
  242. }
  243.  
  244. /*****************************************************************************
  245. * Routine to get close paren token from f.                     *
  246. *****************************************************************************/
  247. static void SkipToCloseParenToken(FILE *f)
  248. {
  249.     char StringToken[LINE_LEN_LONG];
  250.  
  251.     while (!feof(f) && GetToken(f, StringToken) != TOKEN_CLOSE_PAREN);
  252. }
  253.  
  254. /*****************************************************************************
  255. * Routine to get one numeric token into r.                     *
  256. *****************************************************************************/
  257. static void GetNumericToken(FILE *f, RealType *r)
  258. {
  259.     char StringToken[LINE_LEN_LONG];
  260.  
  261.     GetToken(f, StringToken);
  262. #   ifdef DOUBLE
  263.     if (sscanf(StringToken, "%lf", r) != 1)
  264. #   else
  265.     if (sscanf(StringToken, "%f", r) != 1)
  266. #   endif /* DOUBLE */
  267.         ParserError(IP_ERR_NUMBER_EXPECTED, StringToken);
  268. }
  269.  
  270. /*****************************************************************************
  271. * Routine to read the content of a single object. Return TRUE if data is     *
  272. * useful for this parser, FALSE if data should be purged.             *
  273. *****************************************************************************/
  274. static void IritPrsrGetAuxObject(FILE *f, IPObjectStruct *PObj)
  275. {
  276.     int    i, j, ErrLine;
  277.     TokenType Token;
  278.     char *ErrStr, StringToken[LINE_LEN_LONG];
  279.     IPPolygonStruct *PPolygon;
  280.     CagdCrvStruct *PCurve;
  281.     CagdSrfStruct *PSurface;
  282.  
  283.     PObj -> Type = IP_OBJ_UNDEF;
  284.  
  285.     while (GetToken(f, StringToken) == TOKEN_OPEN_PAREN) {
  286.     switch (Token = GetToken(f, StringToken)) {
  287.         case TOKEN_POLYGON:
  288.         case TOKEN_POLYLINE:
  289.         case TOKEN_POINTLIST:
  290.         PPolygon = IritPrsrNewPolygonStruct();
  291.         switch (Token) {
  292.             case TOKEN_POLYGON:
  293.             PPolygon -> Type = IP_POLYGON;
  294.             break;
  295.             case TOKEN_POLYLINE:
  296.             PPolygon -> Type = IP_POLYLINE;
  297.             break;
  298.             case TOKEN_POINTLIST:
  299.             PPolygon -> Type = IP_POINTLIST;
  300.             break;
  301.         }
  302.  
  303.         /* The following handle the optional attributes in struct.   */
  304.         if (GetToken(f, StringToken) == TOKEN_OPEN_PAREN)
  305.             GetPolygonAttributes(PPolygon, f);
  306.         else
  307.             UnGetToken(StringToken);
  308.  
  309.         /* The following handles reading the vertices. */
  310.         GetPointData(f, PPolygon);
  311.  
  312.         if (PPolygon -> Type == IP_POLYGON &&
  313.             !IP_HAS_POLY_PLANE(PPolygon))
  314.             IPUpdatePolyPlane(PPolygon);
  315.  
  316.         PPolygon -> Pnext = PObj -> U.PPolygon;
  317.         PObj -> U.PPolygon = PPolygon;
  318.         PObj -> Type = IP_OBJ_POLY;
  319.         break;
  320.         case TOKEN_MATRIX:
  321.         if (strcmp(PObj -> Name, "VIEW_MAT") == 0) {
  322.             IritPrsrWasViewMat = TRUE;
  323.             for (i = 0; i < 4; i++)
  324.             for (j = 0; j < 4; j++)
  325.                 GetNumericToken(f, &IritPrsrViewMat[i][j]);
  326.             GetCloseParenToken(f);
  327.         }
  328.         else if (strcmp(PObj -> Name, "PRSP_MAT") == 0) {
  329.             IritPrsrWasPrspMat = TRUE;
  330.             for (i = 0; i < 4; i++)
  331.             for (j = 0; j < 4; j++)
  332.                 GetNumericToken(f, &IritPrsrPrspMat[i][j]);
  333.             GetCloseParenToken(f);
  334.         }
  335.         else
  336.             SkipToCloseParenToken(f);
  337.         break;
  338.         case TOKEN_SURFACE:
  339.         ErrLine = GlblLineCount;
  340.         PSurface = CagdSrfReadFromFile2(f, &ErrStr, &ErrLine);
  341.         GlblLineCount = ErrLine;
  342.  
  343.         if (ErrStr != NULL) {
  344.             ParserError(IP_ERR_CAGD_LIB_ERR, ErrStr);
  345.             break;
  346.         }
  347.  
  348.         if (PSurface != NULL) {
  349.             PSurface -> Pnext = PObj -> U.PSrfs;
  350.             PObj -> U.PSrfs = PSurface;
  351.         }
  352.         PObj -> Type = IP_OBJ_SURFACE;
  353.         break;
  354.         case TOKEN_CURVE:
  355.         ErrLine = GlblLineCount;
  356.         PCurve = CagdCrvReadFromFile2(f, &ErrStr, &ErrLine);
  357.         GlblLineCount = ErrLine;
  358.  
  359.         if (ErrStr != NULL) {
  360.             ParserError(IP_ERR_CAGD_LIB_ERR, ErrStr);
  361.             break;
  362.         }
  363.  
  364.         if (PCurve != NULL) {
  365.             PCurve -> Pnext = PObj -> U.PCrvs;
  366.             PObj -> U.PCrvs = PCurve;
  367.         }
  368.         PObj -> Type = IP_OBJ_CURVE;
  369.         break;
  370.         case TOKEN_NUMBER:
  371.         case TOKEN_STRING:
  372.         case TOKEN_VECTOR:
  373.         case TOKEN_CTLPT:
  374.         SkipToCloseParenToken(f);
  375.         break;
  376.         default:
  377.         ParserError(IP_ERR_UNDEF_EXPR_HEADER, StringToken);
  378.         break;
  379.     } /* Of switch. */
  380.     } /* Of while. */
  381.  
  382.     switch (Token) {
  383.         case TOKEN_POLYGON:
  384.         case TOKEN_POLYLINE:
  385.         case TOKEN_POINTLIST:
  386.         PObj -> Pnext = AllPolys;
  387.         AllPolys = PObj;
  388.             break;
  389.         case TOKEN_SURFACE:
  390.         PObj -> Pnext = AllSrfs;
  391.         AllSrfs = PObj;
  392.             break;
  393.         case TOKEN_CURVE:
  394.         PObj -> Pnext = AllCrvs;
  395.         AllCrvs = PObj;
  396.             break;
  397.         default:
  398.             free((VoidPtr) PObj);
  399.             break;
  400.     }
  401.  
  402.     UnGetToken(StringToken);
  403. }
  404.  
  405. /*****************************************************************************
  406. *   Routine to unget one token (on stack of UNGET_STACK_SIZE levels!)         *
  407. *****************************************************************************/
  408. static void UnGetToken(char *StringToken)
  409. {
  410.     if (GlblToken >= UNGET_STACK_SIZE)
  411.      ParserError(IP_ERR_STACK_OVERFLOW, "");
  412.  
  413.     strcpy(GlblStringToken[GlblToken], StringToken);
  414.     GlblToken++;  /* GlblToken exists - Something in it (no overflow check). */
  415. }
  416.  
  417. /*****************************************************************************
  418. *   Routine to get the next token out of the input file    f.             *
  419. * Returns the next token found,    as StringToken.                     *
  420. * Note:    StringToken must be allocated before calling this routine!         *
  421. *****************************************************************************/
  422. static void GetStringToken(FILE *f, char *StringToken)
  423. {
  424.     int    len;
  425.     char c, *LocalStringToken;
  426.  
  427.     if (GlblToken) { /*    get first the unget token */
  428.     GlblToken--;
  429.     strcpy(StringToken, GlblStringToken[GlblToken]);
  430.     return;
  431.     }
  432.     /* skip white spaces: */
  433.     while ((!feof(f))
  434.      && (((c = getc(f)) == ' ') || (c == '\t') || (c == '\n')))
  435.         if (c == '\n') GlblLineCount++;         /* Count the lines. */
  436.  
  437.     LocalStringToken = StringToken;
  438.     if (c == '[')              /* Its a token by    itself so return it. */
  439.     *LocalStringToken++ = c;          /* Copy the token    into string. */
  440.     else {
  441.     if (!feof(f))
  442.          do    *LocalStringToken++ = c;      /* Copy the token    into string. */
  443.          while ((!feof(f)) &&
  444.               ((c = getc(f)) !=    ' ') &&    (c != '\t') && (c != '\n'));
  445.     if (c == '\n') ungetc(c, f);     /* Save it to be counted next time. */
  446.     }
  447.     *LocalStringToken =    0;                     /* Put    eos. */
  448.  
  449.     /* The following handles the spacial case were we have XXXX] - we must   */
  450.     /* split it    into two token XXXX and    ], UnGetToken(']') and return XXXX:  */
  451.     if ((StringToken[len = strlen(StringToken)-1] == ']') && (len > 0))    {
  452.     /* Return CloseParan */
  453.     UnGetToken(&StringToken[len]);             /* Save next token. */
  454.     StringToken[len] = 0;            /* Set end of string on    "]". */
  455.     }
  456. }
  457.  
  458. /*****************************************************************************
  459. *   Routine to get the next token out of the input file    f as token number.   *
  460. * Note:    StringToken must be allocated before calling this routine!         *
  461. *****************************************************************************/
  462. static TokenType GetToken(FILE *f, char *StringToken)
  463. {
  464.     static int IntTokens[] = {
  465.     TOKEN_OPEN_PAREN,
  466.     TOKEN_CLOSE_PAREN,
  467.     TOKEN_VERTEX,
  468.     TOKEN_POLYGON,
  469.     TOKEN_POLYLINE,
  470.     TOKEN_POINTLIST,
  471.     TOKEN_OBJECT,
  472.     TOKEN_COLOR,
  473.     TOKEN_RGB,
  474.     TOKEN_INTERNAL,
  475.     TOKEN_NORMAL,
  476.     TOKEN_PLANE,
  477.     TOKEN_CURVE,
  478.     TOKEN_SURFACE,
  479.     TOKEN_E2,
  480.     TOKEN_P2,
  481.     TOKEN_E3,
  482.     TOKEN_P3,
  483.     TOKEN_NUMBER,
  484.     TOKEN_STRING,
  485.     TOKEN_VECTOR,
  486.     TOKEN_MATRIX,
  487.     TOKEN_CTLPT,
  488.     0
  489.     };
  490.     static char *StrTokens[] = {
  491.     "[",
  492.     "]",
  493.     "VERTEX",
  494.     "POLYGON",
  495.     "POLYLINE",
  496.     "POINTLIST",
  497.     "OBJECT",
  498.     "COLOR",
  499.     "RGB",
  500.     "INTERNAL",
  501.     "NORMAL",
  502.     "PLANE",
  503.     "CURVE",
  504.     "SURFACE",
  505.     "E2",
  506.     "P2",
  507.     "E3",
  508.     "P3",
  509.     "NUMBER",
  510.     "STRING",
  511.     "VECTOR",
  512.     "MATRIX",
  513.     "CTLPT",
  514.     NULL
  515.     };
  516.     int i;
  517.  
  518.     GetStringToken(f, StringToken);
  519.  
  520.     if (feof(f)) return TOKEN_EOF;
  521.  
  522.     for (i = 0; StrTokens[i] != NULL; i++)
  523.     if (strcmp(StringToken, StrTokens[i]) == 0) return IntTokens[i];
  524.  
  525.     return TOKEN_OTHER;                  /* Must be number or name. */
  526. }
  527.  
  528. /*****************************************************************************
  529. * Routine to read from input file f the    following [ATTR ...] [ATTR ...].     *
  530. * Note the '[' was allready read.                         *
  531. *****************************************************************************/
  532. static void GetVertexAttributes(IPVertexStruct *PVertex, FILE *f)
  533. {
  534.     int i;
  535.     RealType Len;
  536.     char StringToken[LINE_LEN_LONG];
  537.  
  538.     do {
  539.     switch (GetToken(f, StringToken)) {
  540.         case TOKEN_INTERNAL:
  541.         GetCloseParenToken(f);
  542.         IP_SET_VRTX_INTERNAL(PVertex);
  543.         break;
  544.         case TOKEN_NORMAL:
  545.         /* The following handles reading 3 coord. of vertex normal. */
  546.         for (i = 0; i < 3; i++)
  547.             GetNumericToken(f, &PVertex -> Normal[i]);
  548.  
  549.         /* Make sure it is normalized. */
  550.         Len = PT_LENGTH(PVertex -> Normal);
  551.         for (i = 0; i < 3; i++) PVertex -> Normal[i] /= Len;
  552.  
  553.         GetCloseParenToken(f);
  554.         IP_SET_VRTX_NORMAL(PVertex);
  555.         break;
  556.         default: /* Ignore this option! */
  557.         SkipToCloseParenToken(f);
  558.         break;
  559.     }
  560.     }
  561.     while (GetToken(f, StringToken) == TOKEN_OPEN_PAREN);
  562.  
  563.     UnGetToken(StringToken);
  564. }
  565.  
  566. /*****************************************************************************
  567. * Routine to read from input file f the    following [ATTR ...] [ATTR ...].     *
  568. * Note the '[' was allready read.                         *
  569. *****************************************************************************/
  570. static void GetPolygonAttributes(IPPolygonStruct *PPolygon, FILE *f)
  571. {
  572.     int i;
  573.     RealType Len;
  574.     char StringToken[LINE_LEN_LONG];
  575.  
  576.     do {
  577.     switch (GetToken(f, StringToken)) {
  578.         case TOKEN_PLANE:
  579.         /* The following handles reading of 4 coord. of plane eqn.. */
  580.         for (i = 0; i < 4; i++)
  581.             GetNumericToken(f, &PPolygon -> Plane[i]);
  582.  
  583.         /* Make sure it is normalized. */
  584.         Len = PT_LENGTH(PPolygon -> Plane);
  585.         for (i = 0; i < 4; i++) PPolygon -> Plane[i] /= Len;
  586.  
  587.         GetCloseParenToken(f);
  588.         IP_SET_POLY_PLANE(PPolygon);
  589.         break;
  590.         default:
  591.         SkipToCloseParenToken(f);
  592.         break;
  593.     }
  594.     }
  595.     while (GetToken(f, StringToken) == TOKEN_OPEN_PAREN);
  596.  
  597.     UnGetToken(StringToken);
  598. }
  599.  
  600. /*****************************************************************************
  601. * Routine to read from input file f the    following [ATTR ...] [ATTR ...].     *
  602. * Note the '[' was allready read.                         *
  603. *****************************************************************************/
  604. static void GetObjectAttributes(IPObjectStruct *PObject, FILE *f)
  605. {
  606.     int    i, j;
  607.     char StringToken[LINE_LEN_LONG];
  608.  
  609.     do {
  610.     switch (GetToken(f, StringToken)) {
  611.         case TOKEN_RGB:
  612.         /* The following handles reading of 3 coord. of rgb.    */
  613.         for (i = 0; i < 3; i++) {
  614.             GetToken(f, StringToken);
  615.             if (sscanf(StringToken, "%d", &j) != 1)
  616.             ParserError(IP_ERR_NUMBER_EXPECTED, StringToken);
  617.             PObject -> RGB[i] = (unsigned char) j;
  618.         }
  619.         GetCloseParenToken(f);
  620.         IP_SET_OBJ_RGB(PObject);
  621.         break;
  622.         case TOKEN_COLOR:
  623.         GetToken(f, StringToken);
  624.         if (sscanf(StringToken, "%d", &i) != 1)
  625.             ParserError(IP_ERR_NUMBER_EXPECTED, StringToken);
  626.         GetCloseParenToken(f);
  627.         PObject -> Color = i;
  628.         IP_SET_OBJ_COLOR(PObject);
  629.         break;
  630.         default:
  631.         if ((i = PObject -> Attrs.NumStrAttribs) < MAX_NUM_ATTRS)
  632.         {
  633.            PObject -> Attrs.StrAttrName[i] = strdup(StringToken);
  634.            if (GetToken(f, StringToken) == TOKEN_CLOSE_PAREN) {
  635.                UnGetToken(StringToken);
  636.                PObject -> Attrs.StrAttrData[i] = "";
  637.            }
  638.            else {
  639.                PObject -> Attrs.StrAttrData[i] = strdup(StringToken);
  640.            }
  641.            PObject -> Attrs.NumStrAttribs++;
  642.         }
  643.         SkipToCloseParenToken(f);
  644.         break;
  645.     }
  646.     }
  647.     while (GetToken(f, StringToken) == TOKEN_OPEN_PAREN);
  648.  
  649.     if (!IP_HAS_OBJ_COLOR(PObject)) {
  650.     PObject -> Color = LOAD_COLOR;
  651.     IP_SET_OBJ_COLOR(PObject);
  652.     }
  653.  
  654.     UnGetToken(StringToken);
  655. }
  656.  
  657. /*****************************************************************************
  658. * Routine to read poly* vertex information.                     *
  659. *****************************************************************************/
  660. static void GetPointData(FILE *f, IPPolygonStruct *PPolygon)
  661. {
  662.     int i, j, Length;
  663.     char StringToken[LINE_LEN_LONG];
  664.     IPVertexStruct *V,
  665.     *VTail = NULL;
  666.  
  667.     if (GetToken(f, StringToken) != TOKEN_OTHER ||
  668.     sscanf(StringToken, "%d", &Length) != 1)
  669.     ParserError(IP_ERR_NUMBER_EXPECTED, StringToken);
  670.  
  671.     for (i = 0; i < Length; i++) {
  672.     if (GetToken(f, StringToken) != TOKEN_OPEN_PAREN)
  673.         ParserError(IP_ERR_OPEN_PAREN_EXPECTED, StringToken);
  674.  
  675.     V = IritPrsrNewVertexStruct();
  676.  
  677.     /* The following handle the optional attributes in struct. */
  678.     if (GetToken(f, StringToken) == TOKEN_OPEN_PAREN)
  679.         GetVertexAttributes(V, f);
  680.     else
  681.         UnGetToken(StringToken);
  682.  
  683.     for (j = 0; j < 3; j++)                /* Read coordinates. */
  684.         GetNumericToken(f, &V -> Coord[j]);
  685.  
  686.     GetCloseParenToken(f);
  687.  
  688.     if (!IP_HAS_VRTX_NORMAL(V))
  689.         PT_COPY(V -> Normal, PPolygon -> Plane);
  690.  
  691.     if (VTail == NULL)
  692.         PPolygon -> PVertex = VTail = V;
  693.     else {
  694.         VTail -> Pnext = V;
  695.         VTail = V;
  696.     }
  697.     }
  698.  
  699.     if (IritPrsrPolyListCirc && PPolygon -> Type == IP_POLYGON)
  700.     VTail -> Pnext = PPolygon -> PVertex;
  701.  
  702.     GetCloseParenToken(f);
  703. }
  704.  
  705. /*****************************************************************************
  706. *   Routine to update the Plane equation of the given polygon by the order   *
  707. * of the first 3 vertices of that polygon.                     *
  708. *****************************************************************************/
  709. static void IPUpdatePolyPlane(IPPolygonStruct *PPoly)
  710. {
  711.     int i;
  712.     RealType Len, V1[3], V2[3];
  713.     IPVertexStruct *V = PPoly -> PVertex;
  714.  
  715.     if (V == NULL || V -> Pnext == NULL || V -> Pnext -> Pnext == NULL)
  716.     ParserError(IP_ERR_DEGEN_POLYGON, "");
  717.  
  718.     PT_SUB(V1, V -> Coord, V -> Pnext -> Coord);
  719.     V = V -> Pnext;
  720.     PT_SUB(V2, V -> Coord, V -> Pnext -> Coord);
  721.  
  722.     PPoly -> Plane[0] = V1[1] * V2[2] - V2[1] * V1[2];
  723.     PPoly -> Plane[1] = V1[2] * V2[0] - V2[2] * V1[0];
  724.     PPoly -> Plane[2] = V1[0] * V2[1] - V2[0] * V1[1];
  725.     PPoly -> Plane[3] = (-DOT_PROD(PPoly -> Plane, PPoly -> PVertex -> Coord));
  726.  
  727.     /* Normalize the plane such that the normal has length of 1: */
  728.     Len = PT_LENGTH(PPoly -> Plane);
  729.     for (i = 0; i < 4; i++) PPoly -> Plane[i] /= Len;
  730. }
  731.  
  732. /*****************************************************************************
  733. *   Routine to set a string attribute. A string attribute consists of an     *
  734. * attribute name (string) and data (also string).                 *
  735. *   If Data = "", the attribute with name Name is been freed.             *
  736. *   If attribute by the given name already exists, it is replaced.         *
  737. *****************************************************************************/
  738. void IritPrsrSetStrAttrib(IPObjectStruct *PObj, char *Name, char *Data)
  739. {
  740.     int i;
  741.     IPAttributeStruct *Attr = &PObj -> Attrs;
  742.  
  743.     for (i = 0; i < Attr -> NumStrAttribs; i++) {
  744.     if (strcmp(Name, Attr -> StrAttrName[i]) == 0) {
  745.         /* If Data is an empty string, remove this entry. */
  746.         if (strlen(Data) == 0) {
  747.         free((VoidPtr) Attr -> StrAttrName[i]);
  748.         free((VoidPtr) Attr -> StrAttrData[i]);
  749.         for ( ; i < (int) Attr -> NumStrAttribs - 2; i++) {
  750.             Attr -> StrAttrName[i] = Attr -> StrAttrName[i + 1];
  751.             Attr -> StrAttrData[i] = Attr -> StrAttrData[i + 1];
  752.         }
  753.         Attr -> NumStrAttribs--;
  754.         }
  755.         else {
  756.         free((VoidPtr) Attr -> StrAttrData[i]);
  757.         Attr -> StrAttrData[i] = strdup(Data);
  758.         }
  759.  
  760.         return;
  761.     }
  762.     }
  763.  
  764.     /* O.k. it is a new attribute. */
  765.     if (Attr -> NumStrAttribs >= MAX_NUM_ATTRS) {
  766.     return;
  767.     }
  768.     Attr -> StrAttrName[Attr -> NumStrAttribs] = strdup(Name);
  769.     Attr -> StrAttrData[Attr -> NumStrAttribs++] = strdup(Data);
  770. }
  771.  
  772. /*****************************************************************************
  773. *   Routine to get a string attribute. A string attribute consists of an     *
  774. * attribute name (string) and data (also string).                 *
  775. *   Returns a pointer to data if string name is found, NULL otherwise.         *
  776. *****************************************************************************/
  777. char *IritPrsrGetStrAttrib(IPObjectStruct *PObj, char *Name)
  778. {
  779.     int i;
  780.     IPAttributeStruct *Attr = &PObj -> Attrs;
  781.  
  782.     /* If Name is an empty string - print all attributes. */
  783.     if (Name == NULL || strlen(Name) == 0) return NULL;
  784.  
  785.     for (i = 0; i < Attr -> NumStrAttribs; i++)
  786.     if (strcmp(Name, Attr -> StrAttrName[i]) == 0)
  787.             return Attr -> StrAttrData[i];
  788.  
  789.     return NULL;
  790. }
  791.  
  792. /*****************************************************************************
  793. * Routine to allocate a new VertexStruct.                     *
  794. *****************************************************************************/
  795. IPVertexStruct *IritPrsrNewVertexStruct(void)
  796. {
  797.     IPVertexStruct *V = (IPVertexStruct *) malloc(sizeof(IPVertexStruct));
  798.     V -> Pnext = NULL;
  799.     V -> VAux = NULL;
  800.     V -> VTags = 0;
  801.     return V;
  802. }
  803.  
  804. /*****************************************************************************
  805. * Routine to allocate a new PolygonStruct.                     *
  806. *****************************************************************************/
  807. IPPolygonStruct *IritPrsrNewPolygonStruct(void)
  808. {
  809.     IPPolygonStruct *P = (IPPolygonStruct *) malloc(sizeof(IPPolygonStruct));
  810.     P -> Pnext = NULL;
  811.     P -> PVertex = NULL;
  812.     P -> PAux = NULL;
  813.     P -> PTags = 0;
  814.     return P;
  815. }
  816.  
  817. /*****************************************************************************
  818. * Routine to allocate a new ObjectStruct.                     *
  819. *****************************************************************************/
  820. IPObjectStruct *IritPrsrNewObjectStruct(void)
  821. {
  822.     IPObjectStruct *O = (IPObjectStruct *) malloc(sizeof(IPObjectStruct));
  823.     O -> Pnext = NULL;
  824.     O -> U.PPolygon = NULL;
  825.     O -> OAux = NULL;
  826.     O -> Attrs.NumStrAttribs = 0;
  827.     O -> OTags = 0;
  828.     O -> Name[0] = 0;
  829.     O -> Color = LOAD_COLOR;
  830.     O -> FFPolylines = O -> FFPolygons = NULL;
  831.     return O;
  832. }
  833.  
  834. /*****************************************************************************
  835. * Routine to print pasring error according to ErrNum and set GlblParserError.*
  836. *****************************************************************************/
  837. static void ParserError(IritPrsrErrType ErrNum, char *Msg)
  838. {
  839.     IPGlblLineCount = GlblLineCount;
  840.     IPGlblParserError = ErrNum;
  841.     strcpy(IPGlblTokenError, Msg);    /* Keep the message in safe place... */
  842.  
  843.     longjmp(LclLongJumpBuffer, 1);                   /* Jump to... */
  844. }
  845.  
  846. /*****************************************************************************
  847. * Returns TRUE if error happened, FALSE otherwise.                 *
  848. *   If error, then ErrorMsg is updated to point on static str describing it. *
  849. *****************************************************************************/
  850. int IritPrsrParseError(char **ErrorMsg)
  851. {
  852.     IritPrsrErrType Temp;
  853.     char TempCopy[LINE_LEN_LONG];
  854.  
  855.     if ((Temp = IPGlblParserError) == IP_NO_ERR) return FALSE;
  856.  
  857.     strcpy(TempCopy, IPGlblTokenError);
  858.     IPGlblParserError = IP_NO_ERR;
  859.  
  860.     switch (Temp) {
  861.     case IP_ERR_NUMBER_EXPECTED:
  862.         sprintf(IPGlblTokenError, "Line %d: Numeric data expected - found %s",
  863.         IPGlblLineCount, TempCopy);
  864.         break;
  865.     case IP_ERR_OPEN_PAREN_EXPECTED:
  866.         sprintf(IPGlblTokenError, "Line %d: '[' expected - found '%s'",
  867.         IPGlblLineCount, TempCopy);
  868.         break;
  869.     case IP_ERR_CLOSE_PAREN_EXPECTED:
  870.         sprintf(IPGlblTokenError, "Line %d: ']' expected - found '%s'",
  871.         IPGlblLineCount, TempCopy);
  872.         break;
  873.     case IP_ERR_LIST_COMP_UNDEF:
  874.         sprintf(IPGlblTokenError, "Line %d: Undefined list element - \"%s\"",
  875.         IPGlblLineCount, TempCopy);
  876.         break;
  877.     case IP_ERR_UNDEF_EXPR_HEADER:
  878.         sprintf(IPGlblTokenError, "Line %d: Undefined TOKEN - \"%s\"",
  879.         IPGlblLineCount, TempCopy);
  880.         break;
  881.     case IP_ERR_PT_TYPE_EXPECTED:
  882.         sprintf(IPGlblTokenError, "Line %d: Point type expected",
  883.         IPGlblLineCount);
  884.         break;
  885.     case IP_ERR_OBJECT_EMPTY:
  886.         sprintf(IPGlblTokenError, "Line %d: Empty object found",
  887.         IPGlblLineCount);
  888.         break;
  889.     case IP_ERR_MIXED_TYPES:
  890.         sprintf(IPGlblTokenError,
  891.             "Line %d: Mixed data types in same object",
  892.             IPGlblLineCount);
  893.         break;
  894.     case IP_STR_NOT_IN_QUOTES:
  895.         sprintf(IPGlblTokenError,
  896.             "Line %d: String not in quotes (%s)",
  897.             IPGlblLineCount, TempCopy);
  898.         break;
  899.     case IP_ERR_OBJECT_EXPECTED:
  900.         sprintf(IPGlblTokenError,
  901.             "Line %d: 'OBJECT' expected, found '%s'",
  902.             IPGlblLineCount, TempCopy);
  903.         break;
  904.     case IP_ERR_CAGD_LIB_ERR:
  905.         sprintf(IPGlblTokenError, "Line %d: %s",
  906.             IPGlblLineCount, TempCopy);
  907.         break;
  908.     case IP_ERR_STACK_OVERFLOW:
  909.         sprintf(IPGlblTokenError, "Line %d: Parser Stack overflow",
  910.             IPGlblLineCount);
  911.         break;
  912.     default:
  913.         sprintf(IPGlblTokenError,
  914.             "Line %d: Data file parser - undefined error",
  915.             IPGlblLineCount);
  916.         break;
  917.     }
  918.  
  919.     *ErrorMsg = IPGlblTokenError;
  920.  
  921.     return TRUE;
  922. }
  923.